﻿using System;
using System.ComponentModel;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using Microsoft.Expression.Extensibility;
using Microsoft.Expression.Framework;
using Microsoft.Expression.Framework.Documents;
using Oxage.Common;

namespace Oxage.Printing
{
	public class PrintContractService : IContractService, INotifyPropertyChanged
	{
		#region Constructors
		public PrintContractService()
		{
			this.ProjectType = ProjectTypes.Other;
		}

		public PrintContractService(IServices services) : this()
		{
			RegisterApplicationService(services);
		}
		#endregion

		#region Public properties
		private IServices services;
		public IServices Services
		{
			get
			{
				return this.services;
			}
		}
		#endregion

		#region Public methods
		public void RegisterApplicationService(IServices services)
		{
			this.services = services;
			InitializeAddin();
		}
		#endregion

		#region Protected methods
		protected void InitializeAddin()
		{
			if (services == null)
			{
				ReportError(new Exception("'services' is null, plugin cannot be loaded!"));
			}
			else
			{
				//TODO: Find a better trigger instead of timer
				DispatcherTimer timer = new DispatcherTimer();
				timer.Interval = TimeSpan.FromSeconds(1);
				timer.Tick += (sender, e) =>
				{
					try
					{
						LoadDocumentElement();
					}
					catch (Exception ex)
					{
						OnDebugMessage(ex.Message);
					}
				};
				timer.Start();
			}
		}

		protected void LoadDocumentElement()
		{
			if (services != null)
			{
				var documentService = services.GetService<IDocumentService>();
				var viewService = services.GetService<IViewService>();

				if (documentService != null && viewService != null && this.DocumentPath != documentService.ActiveDocument.DocumentReference.Path)
				{
					#region Find project type
					if (viewService.ActiveView is Microsoft.Expression.DesignSurface.View.WPFSceneView)
					{
						this.ProjectType = ProjectTypes.WPF;
					}
					else if (viewService.ActiveView is Microsoft.Expression.DesignSurface.View.SilverlightSceneView)
					{
						this.ProjectType = ProjectTypes.Silverlight;
					}
					else
					{
						this.ProjectType = ProjectTypes.Other;
					}
					#endregion

					#region Find visual content
					if (this.ProjectType == ProjectTypes.WPF)
					{
						var scene = viewService.ActiveView as Microsoft.Expression.DesignSurface.View.WPFSceneView;
						if (scene != null)
						{
							var artboard = scene.Artboard.ContentArea as Microsoft.Expression.DesignSurface.UserInterface.ArtboardBorder;
							if (artboard != null)
							{
								this.DocumentContent = artboard.Child as FrameworkElement;
								this.DocumentPath = documentService.ActiveDocument.DocumentReference.Path;
								OnDocumentChanged();
							}
						}
					}
					else
					{
						//Experimental, does not work properly with Silverlight
						var scene = viewService.ActiveView as Microsoft.Expression.DesignSurface.View.SceneView;
						if (scene != null)
						{
							this.DocumentContent = scene.Artboard.DesignerView.Child as FrameworkElement;
							this.DocumentPath = documentService.ActiveDocument.DocumentReference.Path;
							OnDocumentChanged();
						}
					}
					#endregion
				}

				if (Settings.Debug)
				{
					#region Build debug message
					StringBuilder builder = new StringBuilder();

					builder.AppendFormat("DocumentPath: {0}", this.DocumentPath).AppendLine();

					if (services == null)
					{
						builder.AppendLine("ApplicationService is null!");
					}
					else if (documentService == null)
					{
						builder.AppendLine("DocumentService is null!");
					}
					else if (documentService.ActiveDocument == null)
					{
						builder.AppendLine("DocumentService.ActiveDocument is null!");
					}
					else if (documentService.ActiveDocument.DocumentReference == null)
					{
						builder.AppendLine("DocumentService.ActiveDocument.DocumentReference is null!");
					}
					else
					{
						builder.AppendFormat("DocumentReference.Path: {0}", documentService.ActiveDocument.DocumentReference.Path).AppendLine();
					}

					if (services != null)
					{
						if (viewService == null)
						{
							builder.AppendLine("ViewService is null!");
						}
						else if (viewService.ActiveView == null)
						{
							builder.AppendLine("ViewService.ActiveView is null!");
						}
						else
						{
							builder.AppendFormat("ActiveView: {0}", viewService.ActiveView.GetType().ToString()).AppendLine();

							var scene = viewService.ActiveView as Microsoft.Expression.DesignSurface.View.SceneView;
							if (scene != null)
							{
								if (scene.Artboard == null)
								{
									builder.AppendLine("Artboard is null!");
								}
								else
								{
									builder.AppendFormat("Artboard: {0}", scene.Artboard.GetType().ToString()).AppendLine();

									var artboard = scene.Artboard.ContentArea as Microsoft.Expression.DesignSurface.UserInterface.ArtboardBorder;
									if (artboard != null)
									{
										builder.AppendFormat("Artboard content: {0}", artboard.Child != null ? artboard.Child.GetType().ToString() : "null").AppendLine();
									}
								}
							}
						}
					}

					OnDebugMessage(builder.ToString());
					#endregion
				}
			}
		}

		protected void ReportError(Exception error)
		{
			if (services != null && error != null)
			{
				var messageLoggingService = services.GetService<IMessageLoggingService>();

				//Display message in application's logging window
				messageLoggingService.WriteLine(error.Message);
			}

			if (Settings.Debug && error != null)
			{
				MessageBox.Show(error.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
			}
		}
		#endregion

		#region IContractService Members
		public string DocumentPath
		{
			get
			{
				return this.documentPath;
			}
			protected set
			{
				if (this.documentPath != value)
				{
					this.documentPath = value;
					OnPropertyChanged("DocumentPath");
				}
			}
		}
		private string documentPath;

		public FrameworkElement DocumentContent
		{
			get
			{
				return this.documentContent;
			}
			protected set
			{
				if (this.documentContent != value)
				{
					this.documentContent = value;
					OnPropertyChanged("DocumentContent");
				}
			}
		}
		private FrameworkElement documentContent;

		public ProjectTypes ProjectType
		{
			get
			{
				return this.projectType;
			}
			protected set
			{
				if (this.projectType != value)
				{
					this.projectType = value;
					OnPropertyChanged("ProjectType");
				}
			}
		}
		private ProjectTypes projectType;

		public void WriteLine(string message)
		{
			if (services != null)
			{
				var messageLoggingService = services.GetService<IMessageLoggingService>();
				messageLoggingService.WriteLine(message);
			}
		}

		public event EventHandler DocumentChanged;
		protected virtual void OnDocumentChanged()
		{
			if (DocumentChanged != null)
			{
				DocumentChanged(this, new EventArgs());
			}
		}

		public event EventHandler<EventArgs<string>> DebugMessage;
		protected virtual void OnDebugMessage(string message)
		{
			if (DebugMessage != null)
			{
				DebugMessage(this, new EventArgs<string>(message));
			}
		}
		#endregion

		#region INotifyPropertyChanged Members
		public event PropertyChangedEventHandler PropertyChanged;
		protected virtual void OnPropertyChanged(string propertyName)
		{
			if (PropertyChanged != null)
			{
				PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
			}
		}
		#endregion
	}
}
